<?php

abstract class Registry{
    abstract  protected function get($key);
    abstract protected function set($key,$val);
}

class ApplicationRegistry extends Registry{
    private static $instance;
    private $freezedir = 'data';
    private $values = array();
    private $mtimes = array();

    private function __construct()
    {
    }

    static function instance(){
        if(!isset(self::$instance)){
            self::$instance = new self();
        }
        return self::$instance;
    }

    protected function get($key)
    {
        $path = $this->freezedir.DIRECTORY_SEPARATOR.$key;
        if(file_exists($path)){
            clearstatcache();
            $mtime = filemtime($path);
            if(!isset($this->mtimes[$key])){
                $this->mtimes[$key] = 0;
            }
            if($mtime>$this->mtimes[$key]){
                $data = file_get_contents($path);
                $this->mtimes[$key] = $mtime;
                return ($this->values[$key] = unserialize($data));
            }
        }
        if(isset($this->values[$key])){
            return $this->values[$key];
        }
        return null;
    }

    protected function set($key, $val)
    {
        $this->values[$key] = $val;
        $path = $this->freezedir.DIRECTORY_SEPARATOR.$key;
        file_put_contents($path,serialize($val));
        $this->mtimes[$key] = time();
    }

    static function getDSN(){
        self::$instance->get('dsn');
    }

    static function setDSN($dsn){
        self::$instance->set('dsn',$dsn);
    }
}

abstract class Mapper{
    protected static $pdo;

    function __construct()
    {
        if(!isset(self::$pdo)){
            $dsn = ApplicationRegistry::getDSN();
            if(is_null($dsn)){
                throw new Exception('NO DSN');
            }
            self::$pdo = new PDO($dsn);
            self::$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
        }

    }

    function find($id){
        $this->selectStmt()->excute(array($id));
        $array = $this->selectStmt()->fetch();
        $this->selectStmt()->closeCursor();
        if(!is_array($array)){return null;}
        if(!isset($id)){return null;}
        $object =$this->createObject($array);
        return $object;
    }

    function createObject($array){
        $obj = $this->doCreateObject($array);
        return $obj;
    }

    function insert(DomainObject $obj){
        $this->doInsert($obj);
    }

    abstract function update(DomainObject $object);

    protected abstract function doCreateObject(array $array);
    protected abstract function doInsert(DomainObject $obj);
    protected abstract function selectStmt();
}